using System;

namespace FixedPointMath
{
    /// <summary>
    /// 角度大于72度之后，不精确性，逐步上升
    /// </summary>
    internal static class TanCotLookup
    {
        /// <summary>
        /// 角度精度: 0.01度
        /// </summary>
        private const long Factor = 100L;

        /// <summary>
        /// 浮动范围
        /// </summary>
        private static Number Float = Number.One / Factor / 2;

        private static readonly int s_90MaxIndex
            ;
        private static readonly int s_180MaxIndex;

        static TanCotLookup()
        {
            s_90MaxIndex = TanCotLookupData.s_Table.Length - 1;
            s_180MaxIndex = s_90MaxIndex + s_90MaxIndex;
        }

        /// <summary>
        /// 获取角度对应的tangent值
        /// </summary>
        /// <param name="degree"></param>
        /// <returns></returns>
        public static Number TanDegree(Number degree)
        {
            if (degree < Number.Zero)
            {
                do
                {
                    degree += Number.N360;
                }
                while (degree < Number.Zero);
            }
            else if (degree > Number.N360)
            {
                do
                {
                    degree -= Number.N360;
                }
                while (degree > Number.N360);
            }

            degree += Float;

            degree.value *= Factor;
            if (degree > Number.N18000)
            {
                degree -= Number.N18000;
            }

            var index = degree.AsInt();
            if (index > s_90MaxIndex)
            {
                index = s_180MaxIndex - index;
                return new Number { value = -TanCotLookupData.s_Table[index] };
            }
            else
            {
                return new Number { value = TanCotLookupData.s_Table[index] };
            }
        }

        /// <summary>
        /// 获取弧度对于的tangent值
        /// </summary>
        /// <param name="radin"></param>
        /// <returns></returns>
        public static Number TanRadin(Number radin)
        {
            return TanDegree(radin * Number.R180 / Number.PI);
        }

        /// <summary>
        /// 获取角度对应的cotangent值
        /// </summary>
        /// <param name="degree"></param>
        /// <returns></returns>
        public static Number CotanDegree(Number degree)
        {
            var n = TanDegree(degree);
            if (n == Number.Zero)
            {
                return Number.MaxValue;
            }
            return Number.N1 / n;
        }

        /// <summary>
        /// 获取弧度对应的cotangent值
        /// </summary>
        /// <param name="radin"></param>
        /// <returns></returns>
        public static Number CotanRadin(Number radin)
        {
            return CotanDegree(radin * Number.R180 / Number.PI);
        }
    }
}
